/*=========================================================================
UberSim Source Code Release
-------------------------------------------------------------------------
Copyright (C) 2002 Manuela Veloso, Brett Browning, Mike Bowling,
                   James Bruce; {mmv, brettb, mhb, jbruce}@cs.cmu.edu
                   Erick Tryzelaar {erickt}@andrew.cmu.edu
School of Computer Science, Carnegie Mellon University
-------------------------------------------------------------------------
This software is distributed under the GNU General Public License,
version 2.  If you do not have a copy of this licence, visit
www.gnu.org, or write: Free Software Foundation, 59 Temple Place,
Suite 330 Boston, MA 02111-1307 USA.  This program is distributed
in the hope that it will be useful, but WITHOUT ANY WARRANTY,
including MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-------------------------------------------------------------------------*/

#include "mmgr.h"

#include "Entity.h"
#include "Node.h"
#include "RigidBody.h"

/*******************************/

Node::Node (char* name) : Spatial (name)
{
	childrenCount = 0;
}

/*******************************/

Node::~Node ()
{
	for (unsigned int i = 0; i < children.size(); i++)
	{
		Spatial* child = removeChild (i);

		if (child)
		{
			delete child;
		}
	}
}

/*******************************/

Spatial* Node::getChild (unsigned int index)
{
	Spatial* child = 0;
	
	if (0 <= index && index < children.size ())
	{
		child = children[index];
	}

	return 0;
}

/*******************************/

unsigned int Node::getChildrenCount ()
{
	return childrenCount;
}

/*******************************/

void Node::addChild (Spatial* child)
{
	if (child)
	{
		childrenCount++;
		
		if (child->getParent ())
		{
			child->getParent ()->removeChild (child);
		}	

		child->setParent (this);

		child->updateGeometricState (0.0);

		for (unsigned int i = 0; i < children.size (); i++)
		{
			if (children[i] == 0)
			{
				children[i] = child;
				return;
			}
		}

		children.push_back (child);
	}
}

/*******************************/

void Node::removeChild (Spatial* child)
{
	if (child)
	{
		for (unsigned int i = 0; i < children.size (); i++)
		{
			if (children[i] == child)
			{
				childrenCount--;
			
				children[i] = 0;

				child->setParent (0);
			}
		}
	}
}

/*******************************/

Spatial* Node::removeChild (unsigned int i)
{
	Spatial* child = 0;
	
	if (0 <= i && i < children.size ())
	{
		child = children[i];

		if (child)
		{
			childrenCount--;

			children[i]     = 0;
			child->setParent (0);
		}
	}

	return child;
}

/*******************************/

unsigned int Node::size ()
{
	return children.size ();
}

/*******************************/

void Node::updateWorldData (Real deltaTime)
{
	Spatial::updateWorldData (deltaTime);

	for (unsigned int i = 0; i < children.size (); i++)
	{
		Spatial* child = children[i];

		if (child)
		{
			child->updateGeometricState (deltaTime);
		}
	}
}

/*******************************/

void Node::updateWorldBound ()
{
	bool isFirstChildFound = false;

	for (unsigned int i = 0; i < children.size (); i++)
	{
		Spatial* child = children[i];

		if (child)
		{
			if (!isFirstChildFound)
			{
				isFirstChildFound = true;
				worldBound        = child->getWorldBound ();
			}
			else
			{
				worldBound += child->getWorldBound ();
			}
		}
	}
}

/*******************************/

void Node::draw ()
{
	for (unsigned int i = 0; i < children.size (); i++)
	{
		Spatial* spatial = children[i];

		if (spatial)
		{
			spatial->draw ();
		}
	}
}

/*******************************/

void Node::collidingWith (Spatial* object)
{
	for (unsigned int i = 0; i < children.size (); i++)
	{
		Spatial* child = children[i];

		if (child)
		{
			child->onCollidingWith (object);
		}
	}
}

/*******************************/
